package com.example.sandbox.helper;

import com.alibaba.fastjson.JSONObject;
import com.example.sandbox.controller.order.model.DownStream58AbstractMchAppRQ;
import com.example.sandbox.controller.order.model.DownStreamAbstractMchAppRQ;
import com.example.sandbox.dto.MchApp;
import com.example.sandbox.dto.MchRedisContext;
import com.example.sandbox.service.MchAppService;
import com.example.sandbox.util.JeepayKit;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import java.util.Objects;

/**
 * @Author Lierbao
 * @Date 2024/6/14 11:58
 */

@Slf4j
@Component
public class MchAndSignCheckHelper {

    @Autowired
    private MchAppService mchAppService;

    /**
     * 请求过期时间
     */
    public static final Long EXPIRED_REQUEST_MINUTES = 5L;

    /**
     * 商户、签名、IP、异步通知地址校验
     *
     * @param request     公共参数
     * @param httpRequest http请求
     * @param notifyUrl   异步通知地址, 为空则不校验
     * @return
     */
    public MchRedisContext mchAndSignAndIPCheckRedis(DownStreamAbstractMchAppRQ request, HttpServletRequest httpRequest, String notifyUrl) {
        MchRedisContext context = new MchRedisContext();
        // 请求参数
        Long reqTime = request.getReqTime();
        String mchNo = request.getMchNo();
        String sign = request.getSign();

        // 校验请求是否过期
        long currentTimeMillis = System.currentTimeMillis();
        if ((currentTimeMillis - reqTime) > (1000 * 60 * EXPIRED_REQUEST_MINUTES)) {
            throw new BizException("Request has expired");//请求已过期
        }

        //==> 缓存
        // 验签
        MchApp mchApp = mchAppService.getOne(MchApp.gw().eq(MchApp::getMchNo, mchNo));
        if (Objects.isNull(mchApp)){
            throw new BizException("Merchant application does not exist or application status is unavailable");//请求已过期
        }
        // 验签
        String appSecret = mchApp.getAppSecret();
        JSONObject bizReqJSON = (JSONObject) JSONObject.toJSON(request);
        bizReqJSON.remove("sign");
        if (!sign.equalsIgnoreCase(JeepayKit.getSign(bizReqJSON, appSecret))) {
            throw new BizException("Signature verification failed");//验签失败
        }
        BeanUtils.copyProperties(mchApp, context);
        return context;
    }

    /**
     * 商户、签名、IP、异步通知地址校验
     *
     * @param request     公共参数
     * @param httpRequest http请求
     * @param notifyUrl   异步通知地址, 为空则不校验
     * @return
     */
    public MchRedisContext mch58AndSignAndIPCheckRedis(DownStream58AbstractMchAppRQ request, HttpServletRequest httpRequest, String notifyUrl) {
        MchRedisContext context = new MchRedisContext();
        // 请求参数
        Long reqTime = request.getReqTime();
        String mchNo = request.getMerchantNo();
        String sign = request.getSign();

        // 校验请求是否过期
        long currentTimeMillis = System.currentTimeMillis();
        if ((currentTimeMillis - reqTime) > (1000 * 60 * EXPIRED_REQUEST_MINUTES)) {
            throw new BizException("Request has expired");//请求已过期
        }

        //==> 缓存
        // 验签
        MchApp mchApp = mchAppService.getOne(MchApp.gw().eq(MchApp::getMchNo, mchNo));
        if (Objects.isNull(mchApp)){
            throw new BizException("Merchant application does not exist or application status is unavailable");//请求已过期
        }
        // 验签
        String appSecret = mchApp.getAppSecret();
        JSONObject bizReqJSON = (JSONObject) JSONObject.toJSON(request);
        bizReqJSON.remove("sign");
        if (!sign.equalsIgnoreCase(JeepayKit.getHmacSHA256Sign(bizReqJSON, appSecret))) {
            throw new BizException("Signature verification failed");//验签失败
        }
        BeanUtils.copyProperties(mchApp, context);
        return context;
    }

}
